﻿using System;
using System.Configuration;
using System.Globalization;
using System.Web;

using BizElements.BusinessLayer;

namespace BizElements.Web
{
    /// <summary>Stores user data in ASP.NET session.</summary>
    /// <remarks><para>User's have access to multilingual text-sources. Text source is initialized by a <see cref="ITextSourceFactory"/> object configured in <b>appSettings</b> section of Web.config file. Example:
    /// <code>
    /// &lt;add key="BizElements.Web.UserSession.TextSourceFactoryAssembly" value="$Variables["SolutionNamespace"]$.Web"/&gt;
    /// &lt;add key="BizElements.Web.UserSession.TextSourceFactoryClass" value="BizElements.Web.UI.MessagesTextResourceFactory"/&gt;
    /// </code></para>
    /// <para>Non-textual data format is specified by <see cref="UserSession.Formatter"/> object for each user. Default formats are configured in <b>appSettings</b> section of Web.config file. Example:
    /// <code>
    /// &lt;add key="BizElements.Web.UserSession.DefaultDateFormat" value="dd.MM.yyyy"/&gt;
    /// &lt;add key="BizElements.Web.UserSession.DefaultRealFormat" value="n2"/&gt;
    /// </code></para>
    /// </remarks>
    public static class UserSession
    {
        #region Configuration.

        /// <summary>Default date format configured in appSettings section ob Web.config file.</summary>
        /// <value>Fofmat configured in <b>BizElements.Web.UserSession.DefaultDateFormat</b> app setting. Default is <b>d</b>.</value>
        /// <remarks>Example: <code>&lt;add key="BizElements.Web.UserSession.DefaultDateFormat" value="d"/&gt;</code></remarks>
        public static readonly string DefaultDateFormat = ConfigurationManager.AppSettings["BizElements.Web.UserSession.DefaultDateFormat"] ?? "d";

        /// <summary>Default real number format configured in appSettings section ob Web.config file.</summary>
        /// <value>Format configured in <b>BizElements.Web.UserSession.DefaultRealFormat</b> app setting. Default is <b>"n2"</b>.</value>
        /// <remarks>Example: <code>&lt;add key="BizElements.Web.UserSession.DefaultRealFormat" value="n2"/&gt;</code></remarks>
        public static readonly string DefaultRealFormat = ConfigurationManager.AppSettings["BizElements.Web.UserSession.DefaultRealFormat"] ?? "n2";

        /// <summary>Text source factory object which creates a text source for each user. Configured in appSettings section ob Web.config file.</summary>
        /// <remarks>Example:<code>
        /// &lt;add key=\"BizElements.Web.UserSession.TextSourceFactoryAssembly\" value=\"MySolution.Web\"/&gt;
        /// &lt;add key=\"BizElements.Web.UserSession.TextSourceFactoryClass\" value=\"BizElements.Web.MessagesTextResourceFactory\"/&gt;
        /// </code></remarks>
        public static readonly ITextSourceFactory TextSourceFactory;

        static readonly string TextSourceFactoryExceptionMessage = "Text source factory class must be configured in appSettings section of Web.config file. Example:" + Environment.NewLine
            + "<add key=\"BizElements.Web.UserSession.TextSourceFactoryAssembly\" value=\"MySolution.Web\"/>" + Environment.NewLine
            + "<add key=\"BizElements.Web.UserSession.TextSourceFactoryClass\" value=\"BizElements.Web.MessagesTextResourceFactory\"/>";

        static UserSession()
        {
            TextSourceFactory = ReflectionUtil.TryCreateInstanceFromAppSettings("BizElements.Web.UserSession.TextSourceFactoryAssembly", "BizElements.Web.UserSession.TextSourceFactoryClass") as ITextSourceFactory;
            if (TextSourceFactory == null)
                throw new InvalidOperationException(TextSourceFactoryExceptionMessage);
        }

        #endregion

        #region InitializeSession.

        /// <summary>Initializes <see cref="MessageSource"/>, <see cref="Formatter"/> and <see cref="UiCulture"/> properties using <b>CultureInfo.CurrentUICulture</b>.
        /// Should be invoked once for each user when a new session is started(Global.Session_Start).</summary>
        public static void InitializeSession()
        {   
            InitializeSession(CultureInfo.CurrentUICulture);
        }

        /// <summary>Initializes <see cref="MessageSource"/>, <see cref="Formatter"/> and <see cref="UiCulture"/>.
        /// Should be invoked once for each user when a new session is started(Global.Session_Start).</summary>
        /// <param name="uiCulture">User culture.</param>
        public static void InitializeSession(CultureInfo uiCulture)
        {
            MessageSource = TextSourceFactory.CreateTextSource();
            UiCulture = uiCulture;
            Formatter = new MessageFormatter(uiCulture) { DateFormat = DefaultDateFormat, RealFormat = DefaultRealFormat };
        }

        #endregion

        /// <summary>Removes all properties from session state.</summary>
        public static void DiscardSession()
        {
            Actor = null;
            Formatter = null;
            MessageSource = null;
            UiCulture = null;
        }

        #region Properties.

        /// <summary>Current actor/user data.</summary>
        public static IActor Actor
        {
            get { return HttpContext.Current.Session["__UserSession.Actor"] as IActor; }
            set 
            {
                if (value != null)
                    HttpContext.Current.Session["__UserSession.Actor"] = value;
                else
                    HttpContext.Current.Session.Remove("__UserSession.Actor");
            }
        }

        /// <summary>Formatting rules used by current user.</summary>
        public static MessageFormatter Formatter
        {
            get { return HttpContext.Current.Session["__UserSession.MessageFormatter"] as MessageFormatter; }
            set 
            {
                if (value != null)
                    HttpContext.Current.Session["__UserSession.MessageFormatter"] = value;
                else
                    HttpContext.Current.Session.Remove("__UserSession.MessageFormatter");
            }
        }

        /// <summary>UI message/text source.</summary>
        public static ITextSource MessageSource
        {
            get { return HttpContext.Current.Session["__UserSession.MessageSource"] as ITextSource; }
            set 
            {
                if (value != null)
                    HttpContext.Current.Session["__UserSession.MessageSource"] = value;
                else
                    HttpContext.Current.Session.Remove("__UserSession.MessageSource");
            }
        }

        /// <summary>UI culture for current user.</summary>
        public static CultureInfo UiCulture
        {
            get { return HttpContext.Current.Session["__UserSession.UiCulture"] as CultureInfo; }
            set 
            {
                if (value != null)
                    HttpContext.Current.Session["__UserSession.UiCulture"] = value;
                else
                    HttpContext.Current.Session.Remove("__UserSession.UiCulture");
            }
        }

        #endregion
    }
}
